home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-20
/
nrd34.zip
/
NRDUTIL.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-06-01
|
51KB
|
1,756 lines
{$I-}
{$V-}
unit nrdutil;
interface
uses crt, dos, graph, screen, nrdio, async;
type prompttype = (PAGE1, PAGE2);
const
LINES = 25;
CHARPERLINE = 80;
BACKTAB = chr(10);
TAB = chr(9);
PAGEUP = chr(3);
PAGEDOWN = chr(4);
UP = chr(15);
DOWN = chr(11);
RIGHTARROW = chr(21);
LEFTARROW = chr(7);
CTRLPAGEUP = chr(14);
CTRLPAGEDN = chr(16);
HOMEKY = chr(5);
ENDKY = chr(6);
MAP_OFFSET = 2.0; { frequency offset from center for sync det. }
{ Receiver window screen limits }
REC_WIN_X_TOP = 1;
REC_WIN_Y_TOP = 1;
REC_WIN_X_BOTTOM = 79;
REC_WIN_Y_BOTTOM = 5;
REVISION = '3.4';
PLOTBUFSIZE = 1024;
type buffer_type = array[0..PLOTBUFSIZE] of byte;
var plot_buffer: buffer_type;
x_pos, y_pos:integer;
prompt_num:prompttype;
enable_s_meter:boolean;
meter_reading:integer;
graphmode:integer;
display_page:integer;
update_receiver_display:boolean;
last_log:integer; { used for hot keying between active and last log }
last_log_data:logtype;{ used to copy data from last log to active log }
i,cnt: integer;
ch:char;
s:string;
oldstat:receivertype;
logentry:logtype;
min_mark,max_mark:word;
rslt:integer;
displayed_freq:array[1..LINES] of real;
displayed_lines:integer;
map:boolean;
procedure sort(var data:sort_array_type; var index:recarraytype;
start, points:integer);
procedure editfield(x,y,fieldlen:integer; number:boolean;
var tabkey, backtabkey:boolean; var val:lstring);
procedure draw_display_titles;
procedure top_window;
procedure bottom_window;
procedure init_rec_window;
procedure status_window;
function precess(var rec:integer; cnt:integer):boolean;
function bandwidth_to_str(bandwidth:bandwidthtype):short_str;
function mode_to_str(mode:modetype):short_str;
function agc_to_str(agc:agctype):short_str;
procedure show_log(rec:integer; refresh_screen,highlight:boolean);
{ refresh_screen = TRUE; paint entire screen with log entries
= FALSE then highlight line if indicated }
procedure write_prompt(s:string);
procedure cmd_prompt(prompt_num:prompttype);
procedure do_help;
procedure timed_s_meter;
procedure show_receiver;
procedure inc_mode;
procedure dec_mode;
procedure inc_bandwidth;
procedure dec_bandwidth;
procedure init_crt;
procedure graph_init;
procedure do_graph;
implementation
procedure sort;
(* THIS PROCEDURE IMPLEMENTS 'QUICKSORT' BY C.A.R. HOARE. THIS N*LOG(N) *)
(* ALGORITHM IS A PARTITION EXCHANGE SORT AND IS DOCUMENTED IN THE 7-80 *)
(* ISSUE OF 'MICRO'. *)
TYPE STACKTYPE = RECORD
UPPER:1..MAXREC; (*STORAGE FOR UPPER SEARCH RANGE*)
LOWER:1..MAXREC (* " " LOWER " " *)
END;
VAR P,Q (*CURRENT LOWER & UPPER INDEX BOUNDS TO BE SORTED. DATA[P] IS
USED AS A COMPARISON KEY IN THE SORTING PROCESS. *)
,I (*STARTS AT P & IS INCREMENTED UNTIL DATA[I]>=DATA[P]. *)
,J (*STARTS AT Q & IS DECREMENTED UNTIL DATA[I]<=DATA[P]. *)
,STACKPTR:INTEGER;
STACK:PACKED ARRAY[1..MAXREC] OF STACKTYPE; (*SEARCH RANGE STORAGE.*)
TEMPDATA,VALUE (*DATA[P]*):short_str;
TEMPINDEX:1..MAXREC;
BEGIN
P:=start; Q:=POINTS + start - 1; STACKPTR:=0;
REPEAT
WHILE P < Q DO
BEGIN
VALUE:=DATA[P]; I:=P; J:=Q + 1;
REPEAT
REPEAT J:=J - 1 UNTIL DATA[J]<=VALUE;
REPEAT inc(I) UNTIL DATA[I]>=VALUE;
IF J > I THEN
BEGIN
TEMPDATA:=DATA[I]; TEMPINDEX:=INDEX[I];
DATA[I] :=DATA[J]; INDEX[I] :=INDEX[J];
DATA[J] :=TEMPDATA;INDEX[J] :=TEMPINDEX
END;
UNTIL J <= I;
TEMPINDEX:=INDEX[P];
DATA[P]:=DATA[J]; INDEX[P]:=INDEX[J];
DATA[J]:=VALUE; INDEX[J]:=TEMPINDEX;
inc(STACKPTR);
IF J - P < Q - J
THEN
WITH STACK[STACKPTR] DO
BEGIN LOWER:=J + 1; UPPER:=Q; Q:=J - 1
END
ELSE
WITH STACK[STACKPTR] DO
BEGIN LOWER:=P; UPPER:=J - 1; P:=J + 1
END;
END; (*WHILE*)
write(output,'.');
IF STACKPTR > 0 THEN (*GRAB NEW SEARCH RANGE OFF STACK*)
WITH STACK[STACKPTR] DO BEGIN Q:=UPPER; P:=LOWER END;
STACKPTR:=STACKPTR-1
UNTIL STACKPTR < 0 (*EMPTY STACK*)
END;
procedure draw_display_titles;
begin
top_window;
gotoxy(1,5);
clreol;
case display_page of
1: begin
gotoxy(2,5);
write(output,'Num');
gotoxy(7,5);
write(output,'Date');
gotoxy(13,5);
write(output,'Strt');
gotoxy(18,5);
write(output,'End');
gotoxy(24,5);
write(output,'Freq');
gotoxy(32,5);
write(output,'Station ID');
gotoxy(52,5);
write(output,'Location');
end;
2: begin
gotoxy(3,5);
write(output,'Freq');
gotoxy(11,5);
write(output,'Comment');
end;
3: begin
gotoxy(2,5);
write(output,'Num');
gotoxy(7,5);
write(output,'Date');
gotoxy(13,5);
write(output,'Strt');
gotoxy(18,5);
write(output,'End');
gotoxy(24,5);
write(output,'Freq');
gotoxy(32,5);
write(output,'Mode');
gotoxy(39,5);
write(output,'BW');
gotoxy(43,5);
write(output,'AGC');
gotoxy(48,5);
write(output,'Attn');
end;
end;
end;
procedure editfield;
{ parameters: x,y = cursor position
fieldlen = allowable length for field
number = flag that if true restricts the keys usable
val = return string }
var ptr,i:integer;
ch:char;
errflg,flag,insert_mode:boolean;
oldval:string[255];
procedure show_line(x,y,fieldlen:integer; val:lstring; edit:boolean);
var i:integer;
lf_bracket,rt_bracket:char;
begin { show_line }
gotoxy(x,y + 1);
if edit then { they are editing this line }
begin
lf_bracket:='[';
rt_bracket:=']';
writea(RED,BACKGROUND);
writea(BLACK,FOREGROUND);
end
else
begin
writea(CYAN,BACKGROUND);
writea(BLACK,FOREGROUND);
lf_bracket:=' ';
rt_bracket:=' ';
end;
write(lf_bracket,val);
gotoxy(x + 1 + fieldlen,y + 1);
write(rt_bracket);
end; { show_line }
procedure blankfill(fieldlen:integer; var val:lstring);
begin
while length(val) < fieldlen do val:=concat(val,' ');
end;
procedure get_normal;
{ fetch normal character and display it. Handle field overflow and
insert_mode }
var i:integer;
s:string[1];
begin
if ptr < fieldlen
then
begin
if ((number) and (ch in ['0'..'9',' ','.']))
or ((ptr = 0) and (ch = '-')) or not number then
begin { all's well }
if not insert_mode then
begin
write(ch); { echo character to screen }
ptr:=ptr + 1;
val[ptr]:=ch
end
else { handle insert mode }
begin
inc(ptr);
for i:=fieldlen downto ptr do val[i]:=val[i - 1];
val[ptr]:=ch;
for i:=ptr to fieldlen do write(val[i]);
gotoxy(x + ptr + 1,y + 1);
end
end
end
end; { get_normal }
procedure do_backspace;
begin
if ptr > 0 then { it's ok to backspace }
begin
ptr:=ptr - 1;
gotoxy(x + ptr + 1,y + 1)
end
end;
procedure do_forwardspace;
begin
if ptr < fieldlen then { its ok to forward space }
begin
inc(ptr);
gotoxy(x + ptr + 1,y + 1)
end
end;
procedure do_del;
var i:integer;
begin
for i:=ptr + 1 to fieldlen - 1 do val[i]:=val[i + 1];
val[fieldlen]:=' ';
for i:=ptr + 1 to fieldlen do write(val[i]);
gotoxy(x + ptr + 1,y + 1);
end;
procedure do_rub;
var i:integer;
begin
if ptr > 0 then ptr:=ptr - 1;
gotoxy(x + ptr + 1,y + 1);
do_del;
end;
procedure toggle_insert;
begin
insert_mode:=not insert_mode;
end;
procedure do_home;
begin
ptr:=0;
gotoxy(x + ptr + 1,y + 1)
end;
procedure do_end;
begin
ptr:=fieldlen;
while (ptr > 0) and (val[ptr] = ' ') do
ptr:=ptr - 1;
gotoxy(x + ptr + 1,y + 1)
end;
procedure do_tab;
begin
tabkey:=TRUE;
ch:=chr(13);
end;
procedure do_backtab;
begin
backtabkey:=TRUE;
ch:=chr(13);
end;
begin { editfield }
insert_mode:=FALSE;
tabkey:=FALSE;
backtabkey:=FALSE;
if number and (val = '-0.00') then val:='0.00';
oldval:=val; { save copy in case they abort }
if length(val) > fieldlen then val:=copy(val,1,fieldlen);
blankfill(fieldlen,val);
ptr:=0;
show_line(x,y,fieldlen,val,TRUE);
gotoxy(x + 1,y + 1);
repeat
ch:=fetch;
if (ch <> chr(13)) and (ord(ch) >= ord(' ')) then get_normal
else if ch = keyinfo.bskey then do_backspace
else if ch = keyinfo.fskey then do_forwardspace
else if ch = keyinfo.delkey then do_del
else if ch = keyinfo.rubkey then do_rub
else if ch = keyinfo.inskey then toggle_insert
else if ch = keyinfo.homekey then do_home
else if ch = keyinfo.endkey then do_end
else if ch = keyinfo.tabkey then do_tab
else if ch = keyinfo.backtabkey then do_backtab
until (ch = chr(13)) or (ch = keyinfo.esckey);
if number then { strip off trailing blanks }
begin
ptr:=length(val);
flag:=TRUE;
while (ptr > 0) and flag do
begin
flag:=val[ptr] = ' ';
if flag then delete(val,ptr,1);
ptr:=ptr - 1;
end;
end;
show_line(x,y,fieldlen,val,FALSE);
end; { editfield }
procedure top_window;
begin
window(REC_WIN_X_TOP,REC_WIN_Y_TOP,REC_WIN_X_BOTTOM+1,REC_WIN_Y_BOTTOM);
end;
procedure bottom_window;
begin
window(1,REC_WIN_Y_BOTTOM + 1, 80,24);
gotoxy(x_pos,y_pos);
end;
procedure init_rec_window;
procedure draw_box(width,hieght:integer);
const TL = chr(201);
TR = chr(187);
BL = chr(200);
BR = chr(188);
HZ = chr(205);
VT = chr(186);
var i:integer;
procedure draw_horiz;
var i:integer;
begin
for i:=1 to width - 2 do write(output,HZ);
end;
begin
{ draw top }
gotoxy(1,2);
write(output,TL);
draw_horiz;
write(output,TR);
{ draw sides }
for i:=1 to hieght - 2 do
begin
gotoxy(1,i + 2); write(output,VT);
gotoxy(width, i + 2); write(output,VT);
end;
{ draw bottom }
gotoxy(1,hieght + 1);
write(output,BL);
draw_horiz;
write(output,BR);
end;
begin
top_window;
writea(BLACK,BACKGROUND);
home;
cmd_prompt(prompt_num);
writea(BROWN,FOREGROUND);
draw_box(REC_WIN_X_BOTTOM - REC_WIN_X_TOP + 1,
REC_WIN_Y_BOTTOM - REC_WIN_Y_TOP - 1) ;
gotoxy(30,2);
writea(LIGHTGRAY,FOREGROUND);
if radio_type = 525
then write(output,'NRD 525 Status')
else write(output,'NRD 535 Status');
gotoxy(3,3);
write(output,'Mode:');
gotoxy(15,3);
write(output,'BW:');
gotoxy(29,3);
write(output,'AGC:');
if radio_type = 525 then
begin
gotoxy(42,3);
write(output,'Ch:');
end;
gotoxy(54,3);
write(output,'Freq:');
gotoxy(68,3);
write(output,' khz');
display_page:=1;
writea(LIGHTGRAY,FOREGROUND);
draw_display_titles;
writea(LIGHTGRAY,FOREGROUND);
end;
procedure status_window;
begin
window(1,25,80,25);
gotoxy(1,1);
clreol;
writea(BLACK,BACKGROUND);
writea(LIGHTGRAY, FOREGROUND);
write(output,'Active Log: ');
writea(CYAN, FOREGROUND);
write(output,loglist.log[loglist.currentlog].logname);
if last_log <> 0 then
begin
writea(LIGHTGRAY, FOREGROUND);
write(output,' Inactive Log: ');
writea(CYAN, FOREGROUND);
write(output,loglist.log[last_log].logname);
end;
end;
function mode_to_str;
var s:short_str;
begin
case mode of
RTTY: s:='RTTY';
CW: s:=' CW';
USB: s:='USB';
LSB: s:='LSB';
AM: s:=' AM';
FM: s:=' FM';
FAX: s:='FAX';
ECSS_USB: s:='ECSSu';
ECSS_LSB: s:='ECSSl';
end;
mode_to_str:=s;
end;
function bandwidth_to_str;
var s:short_str;
begin
case bandwidth of
NARR: s:=' NARR';
INTER: s:='INTER';
WIDE: s:=' WIDE';
AUX: s:=' AUX';
end;
bandwidth_to_str:=s;
end;
function agc_to_str;
var s:short_str;
begin
case agc of
FAST: s:='FAST';
SLOW: s:='SLOW';
OFF: s:=' OFF';
end;
agc_to_str:=s;
end;
procedure show_log_line(logdata:logtype;rec,i:word);
procedure show_line1;
begin
write(output,rec:4);
with logdata do
begin
gotoxy(6,i);
write(output,date);
gotoxy(13,i);
write(output,begin_time);
gotoxy(18,i);
write(output,end_time);
gotoxy(23,i);
write(output,frequency:8:2);
gotoxy(32,i);
write(output,callsign);
gotoxy(52,i);
write(output,location);
end;
end;
procedure show_line2;
begin
with logdata do
begin
gotoxy(2,i);
write(output,frequency:8:2);
gotoxy(11,i);
write(output,comment);
end;
end;
procedure show_line3;
var s:short_str;
begin
write(output,rec:4);
with logdata do
begin
gotoxy(6,i);
write(output,date);
gotoxy(13,i);
write(output,begin_time);
gotoxy(18,i);
write(output,end_time);
gotoxy(23,i);
write(output,frequency:8:2);
gotoxy(32,i);
s:=mode_to_str(mode);
write(output,s);
gotoxy(37,i);
s:=bandwidth_to_str(bandwidth);
write(output,s);
gotoxy(43,i);
s:=agc_to_str(agc);
write(output,s);
gotoxy(49,i);
case attenuator of
YES: write(output,'ON');
NO: write(output,'OFF');
end;
end;
end;
begin
gotoxy(1,i); clreol;
case display_page of
1: show_line1;
2: show_line2;
3: show_line3;
end;
end;
function precess;
{ skip cnt displayed records; return TRUE is not past eof }
var i:integer;
begin
for i:=1 to cnt do
begin
rec:=rec + 1;
while (rec < records)
and (recdata.recstat[recdata.recptr[rec]] <> SHOW) do
rec:=rec + 1;
end;
if rec > records then rec:=records;
precess:=recdata.recstat[recdata.recptr[rec]] = SHOW;
end;
procedure show_log;
{ refresh_screen = TRUE; paint entire screen with log entries
= FALSE then highlight line if indicated }
var i,j,x_temp,y_temp:integer;
logdata:logtype;
begin
writea(CYAN,FOREGROUND); writea(BLACK,BACKGROUND);
i:=0; j:=rec - 1;
y_temp:=wherey; { used to highlight cursor line }
x_temp:=wherex;
if refresh_screen then home;
while (i < LINES - REC_WIN_Y_BOTTOM - 1) and (j < records) do
begin
inc(i);
if precess(j,1) then
begin
get_log(logbuf,logdata,recdata.recptr[j]);
displayed_freq[i]:=logdata.frequency;
if (j >= min_mark) and (j <= max_mark) then
begin
writea(BLACK,FOREGROUND);
writea(YELLOW,BACKGROUND);
show_log_line(logdata,j,i);
writea(BLACK,BACKGROUND);
writea(CYAN,FOREGROUND);
end
else if (i = y_temp) and highlight then
begin
writea(BLACK,FOREGROUND);
writea(CYAN,BACKGROUND);
show_log_line(logdata,j,i);
writea(BLACK,BACKGROUND);
writea(CYAN,FOREGROUND);
end
else if refresh_screen or ((i = y_temp) and not highlight)
then show_log_line(logdata,j,i);
end;
end;
displayed_lines:=i;
gotoxy(x_temp,y_temp);
end;
procedure write_prompt;
{ write green prompt at top of top window; leave with light gray foreground
and in top window }
begin
top_window;
writea(GREEN,FOREGROUND);
writea(BLACK,BACKGROUND);
gotoxy(1,1);
clreol;
write(output,s);
writea(LIGHTGRAY,FOREGROUND);
end;
procedure cmd_prompt;
const T0 = 'NRD'+REVISION;
T1 = ': L(og, C(onfirm, S(ort, E(dit, T(une, P(age, H(elp, ';
T2 = 'Q(uit [/]';
T3 = 's-meteR, ';
begin
case prompt_num of
PAGE1: if has_map then write_prompt(T0+T1+'K(iwa, '+T2)
else if radio_type = 525 then write_prompt(T0+T1+T2)
else write_prompt(T0+T1+T3+T2);
PAGE2:write_prompt(T0+
': D(elete, uN(delete, M(ark, U(nmark, J(ournal, A(lternate, W(rite [/]');
end;
end;
procedure do_help;
var ch:char;
procedure help_commands;
var ch:char;
begin
write_prompt('Help -- Receiver display <Hit any key to return>');
window(1,REC_WIN_Y_BOTTOM + 1, 80,25);
home;
writeln(output,
'Commands are designed to be easy to learn and use. All commands are');
writeln(output,
'activated with a single key and are spelled out on the command line. For');
writeln(output,
'example, to log a station, hit "L" (shows up as "L(og" on prompt).');
writeln(output);
writeln(output,'Command Summary:');
writeln(output);
writeln(output,
'/: Toggles command menu (commands from both menus are always active)');
writeln(output,
'L: Log (creates new entry in log, receiver contents automatically included)'
);
writeln(output,
'C: Confirm (updates time, date, receiver contents for highlighted entry)');
writeln(output,
'S: Sort data base with 2 sort keys');
writeln(output,
'E: Edit field where cursor is located. Hit ENTER or a TAB key when done');
writeln(output,
'T: Tune receiver to highlighted entry. Updates all receiver parameters');
writeln(output,
'P: Page right (the contents for an entry span 3 pages, faster than tabs)');
writeln(output,'D: Deletes a log entry');
writeln(output,
'N: uNdeletes a log entry (logging new stations reuses deleted space)');
writeln(output,
'M: Mark line(s) for writing or moving to other datalogs (see Journal)');
writeln(output,'U: Unmark lines');
writeln(output,'A: Alternates between Active and Inactive Logs');
writeln(output,'W: Write entry from Inactive Log to Active Log');
write(output,'Q: Quits the program');
ch:=fetch;
home;
end;
procedure help_more;
var ch:char;
begin
write_prompt('Help -- More Commands <Hit any key to return>');
bottom_window;
home;
writeln(output,
'J: Journal: allows you to select other data logs and do things with them.');
writeln(output,
' I keep multiple logs -- a music log for stations that play');
writeln(output,
' interesting music and target logs for areas I''m trying to get.');
writeln(output,
' Target logs allow you to scan what''s there VERY quickly.');
writeln(output,
' The Write command allows marked areas to be moved from'
);
writeln(output,
' one database to another; like when you find one of those targets!'
);
writeln(output,
' Move is like a write but deletes the marked entry. Print writes');
writeln(output,
' the selected database to your printer. Import will copy data');
writeln(output,
' from Tom Sundstrom''s English Language SW Broadcast Schedules to');
writeln(output,
' this program format. You can order these from Tom (609) 859-2447.'
);
if has_map then
begin
writeln(output,
'K: KIWA (this only applies if you have a KIWA Map unit) "K" toggles KIWA');
writeln(output,
' mode. When enabled, the receiver is placed in AM and the radio');
writeln(output,
' is detuned a couple of Khz for good fidelity. Stations logged or'
);
writeln(output,
' confirmed will be rounded to the nearest 5 Khz. Disabling puts');
writeln(output,
' the radio in ECS mode with the appropriate sideband selected based'
);
writeln(output,
' on the offset. The MAP unit provides synchronous detection for a'
);
writeln(output,
' 525 and was described in Guy Atkin''s 9/90 NASWA article p.18. To'
);
writeln(output,
' tell the program you have a MAP, delete the config.dat file and');
write(output,
' rerun program.');
end;
if radio_type = 535 then
begin
writeln(output,
'R: s-meteR: Toggles mode of periodically updating computer S-Meter display.'
);
writeln(output,
' Unfortunately, reading the S-Meter can cause annoying synthesizer'
);
writeln(output,
' re-locking noise in LSB, USB, CW, and RTTY modes. Use this mode');
writeln(output,
' to disable this when it bothers you');
end;
ch:=fetch;
end;
procedure help_receiver;
var ch:char;
begin
write_prompt('Help -- Receiver display <Hit any key to return>');
bottom_window;
home;
gotoxy(1,3);
writeln(output,
'The box labled "NRD',radio_type
,' Status" contains the last sampled receiver status.'
);
writeln(output,
'Mostly, this is self-explanatory. BW = Bandwidth, Freq is the receiver'
);
writeln(output,
'frequency. If the attenuator is active, you will see "ATT" at the right'
);
writeln(output,
'of the screen. If you said you had a KIWA Map unit and it is active, you'
);
writeln(output,
'will see a "K" at the far right of the status box. The KIWA features are'
);
writeln(output,
'described in the commands section. If you don''t have one, don''t worry'
);
writeln(output,
'about this. Normally, the status is displayed in CYAN unless something'
);
writeln(output,
'has changed since the last sample. Changes are displayed in RED. To cause'
);
writeln(output,
'the receiver status to be sampled, hit any non-command key (like space).'
);
writeln(output,
'This approach to updating the display was chosen deliberately to keep the'
);
write(output,
'radio "unlocked" so you can punch up commands on the radio.');
ch:=fetch;
end;
procedure help_other;
var ch:char;
begin
write_prompt('Help -- Receiver display <Hit any key to return>');
bottom_window;
home;
gotoxy(1,3);
writeln(output,
'There are other useful keys not covered in the command section. First off,'
);
writeln(output,
'all the normal cursor commands work including tabs. HOME takes you to the'
);
writeln(output,
'top of the display log, END takes you to the bottom. Control-PAGE keys'
);
writeln(output,
'work like PAGE keys, only 10 pages at a time. "+" and "-" keys bump the'
);
writeln(output,
'frequency up or down 5 Khz. If you are in USB or LSB mode, the program'
);
writeln(output,
'assumes you are using ECS detection and tunes off 1 Khz for a fraction of'
);
writeln(output,
'a second before tuning in the correct frequency. This feature was added to'
);
writeln(output,
'hear the heterodyne of weak stations you might miss while rapidly scanning.'
);
writeln(output,
'The "<" and ">" keys (or the "," and "." keys so no shifting is needed)'
);
writeln(output,
'decrement or increment the receiver mode. Similarly, the "[" and "]" keys'
);
writeln(output,
'bump the receiver bandwidth selection. "*" will find the closest');
writeln(output,
'log entry for the currently tuned frequency');
writeln(output);
writeln(output,
'The offset from GMT to your computer''s time is stored in the "CONFIG.DAT"'
);
writeln(output,
'file. If this is wrong, delete CONFIG.DAT and the program will prompt you'
);
write(output,
'for the information to correct.');
ch:=fetch;
end;
begin
repeat
bottom_window;
home;
gotoxy(1,8);
writeln(output,
'Type letter for command. For example, to learn more about the receiver');
writeln(output,
'display, type "r". Type "q" to return from the help facility.');
write_prompt(
'Help: R(eceiver display, C(ommands, M(ore commands, O(ther, Q(uit');
ch:=upcase(fetch);
case ch of
'R': help_receiver;
'C': help_commands;
'M': help_more;
'O': help_other;
end;
until ch = 'Q';
cmd_prompt(prompt_num);
bottom_window;
end;
procedure timed_s_meter;
var reading:integer;
begin
x_pos:=wherex; y_pos:=wherey;
if radio_type <> 535 then exit;
check_s_meter(reading);
top_window;
gotoxy(42,3);
writea(LIGHTGRAY,FOREGROUND);
write(output,'S-Meter:');
if (reading > 9)
then writea(RED,FOREGROUND)
else writea(CYAN,FOREGROUND);
write(output,reading:2);
bottom_window;
end;
procedure show_receiver;
var s:string;
procedure do_out(unchanged:boolean; s:string);
begin
if not unchanged then writea(RED,FOREGROUND);
write(output,s);
writea(CYAN,FOREGROUND);
end;
begin
x_pos:=wherex; y_pos:=wherey;
top_window;
writea(CYAN,FOREGROUND);
with receiverstat do
begin
gotoxy(9,3);
case mode of
RTTY: s:='RTTY ';
CW: s:='CW ';
USB: s:='USB ';
LSB: s:='LSB ';
AM: s:='AM ';
FM: s:='FM ';
FAX: s:='FAX ';
ECSS_USB: s:='ECSSu';
ECSS_LSB: s:='ECSSl';
end;
do_out(receiverstat.mode = oldstat.mode,s);
gotoxy(19,3);
case bandwidth of
WIDE: s:='WIDE ';
INTER:s:='INTER';
NARR: s:='NARR ';
AUX: s:='AUX ';
end;
do_out(receiverstat.bandwidth = oldstat.bandwidth,s);
gotoxy(34,3);
case agc of
SLOW: s:='SLOW';
FAST: s:='FAST';
OFF: s:='OFF ';
end;
do_out(receiverstat.agc = oldstat.agc,s);
case attenuator of
YES: s:='ATT';
NO: s:=' ';
end;
gotoxy(74,3);
do_out(receiverstat.attenuator = oldstat.attenuator,s);
if radio_type = 525 then
begin
gotoxy(46,3);
str(channel:3,s);
do_out(receiverstat.channel = oldstat.channel,s);
end;
gotoxy(60,3);
str(frequency:8:2,s);
do_out(receiverstat.frequency = oldstat.frequency,s);
gotoxy(78,3);
if map then write(output,'K') else write(output,' ');
writea(LIGHTGRAY,FOREGROUND);
end;
bottom_window;
oldstat:=receiverstat;
gotoxy(x_pos,y_pos);
end;
procedure inc_mode;
var x_pos,y_pos:integer;
begin
x_pos:=wherex; y_pos:=wherey;
with receiverstat do
begin
remote_on;
if radio_type = 525 then
begin
if mode < FAX
then mode:=succ(mode)
else mode:=RTTY;
end
else { do special case for nrd535 }
begin
case mode of
RTTY: mode:=CW;
CW: mode:=USB;
USB: mode:=LSB;
LSB: mode:=AM;
AM: mode:=ECSS_USB; { change order }
ECSS_USB: mode:=ECSS_LSB;
ECSS_LSB: mode:=FM;
FM: mode:=FAX;
FAX: mode:=RTTY;
end;
end;
set_mode(mode);
remote_off(REMOTE_DLY + 100);
if radio_type = 535 then toggle_remote;
show_receiver;
gotoxy(x_pos,y_pos);
end;
end;
procedure dec_mode;
var x_pos,y_pos:integer;
begin
x_pos:=wherex; y_pos:=wherey;
with receiverstat do
begin
remote_on;
if radio_type = 525 then
begin
if mode > RTTY
then mode:=pred(mode)
else mode:=FAX;
end
else { do special case for nrd535 }
begin
case mode of
RTTY: mode:=FAX;
CW: mode:=RTTY;
USB: mode:=CW;
LSB: mode:=USB;
AM: mode:=LSB;
ECSS_USB: mode:=AM;
ECSS_LSB: mode:=ECSS_USB;
FM: mode:=ECSS_LSB;
FAX: mode:=FM;
end;
end;
set_mode(mode);
remote_off(REMOTE_DLY + 100);
if radio_type = 535 then toggle_remote;
show_receiver;
gotoxy(x_pos,y_pos);
end;
end;
procedure inc_bandwidth;
begin
with receiverstat do
begin
remote_on;
bandwidth:=succ(bandwidth);
set_bandwidth(bandwidth);
remote_off(REMOTE_DLY);
if radio_type = 535 then toggle_remote;
show_receiver;
end;
end;
procedure dec_bandwidth;
begin
with receiverstat do
begin
remote_on;
bandwidth:=pred(bandwidth);
set_bandwidth(bandwidth);
remote_off(REMOTE_DLY);
if radio_type = 535 then toggle_remote;
show_receiver;
end;
end;
procedure init_crt;
begin
home;
init_rec_window;
update_receiver_display:=TRUE;
status_window;
bottom_window;
end;
procedure graph_init;
var graphdriver:integer;
errorcode:integer;
begin
if radio_type = 525 then exit;
graphdriver:=detect;
case graphdriver of
CGA: graphmode:=CGAHI;
MCGA: graphmode:=MCGAHI;
EGA: graphmode:=EGAHI;
EGA64: graphmode:=EGA64HI;
EGAMONO: graphmode:=EGAMONOHI;
IBM8514: graphmode:=IBM8514HI;
HERCMONO:graphmode:=HERCMONOHI;
ATT400: graphmode:=ATT400HI;
VGA: graphmode:=VGAHI;
PC3270: graphmode:=PC3270HI;
end;
initgraph(graphdriver,graphmode,'');
errorcode:=graphresult;
if errorcode <> grok then exit;
restorecrtmode;
home;
end;
procedure do_graph;
const X_INIT = 40;
Y_INIT = 43;
SCALE = 2.0;
Y_SCALE = 480;
X_SCALE = 640;
X_AXIS = X_INIT - 5;
{ constants needed for toggling between the log and a spectral plot }
SPECTRAL_MODE: boolean = FALSE;
start_freq: real = 0.0;
stop_freq: real = 0.0;
type plottype = (NONE, TIME, SPECTRAL);
var count:integer;
reading:integer;
dummy:integer;
max_x,max_y:integer;
max_count:integer;
hour,minute,sec,sec100:word;
last_plot:plottype;
ch:char;
s:string;
function scale_y(reading:integer):integer;
begin
scale_y:=round((reading * SCALE - Y_INIT) * max_y / Y_SCALE);
end;
procedure init_graph;
var y:integer;
procedure draw_tick(reading:integer; db:string);
var y:integer;
begin
y:=scale_y(reading);
moveto(X_AXIS-2,y);
lineto(X_AXIS+5,y);
setcolor(8);
lineto(max_x,y);
setcolor(15);
moveto(X_AXIS-30,y-3);
outtext(db);
end;
begin
setgraphmode(graphmode);
moveto(X_AXIS,scale_y(240));
lineto(X_AXIS,scale_y(60));
draw_tick(67,'');
draw_tick(71,'+50');
draw_tick(75,'');
draw_tick(81,'+30');
draw_tick(87,'');
draw_tick(92,'+10');
draw_tick(99,'+9');
draw_tick(108,'+7');
draw_tick(118,'+5');
draw_tick(133,'+3');
draw_tick(154,'+1');
end;
procedure plot_title(s:string);
var offset:integer;
begin
{ compensate for low res displays to allow room for text }
case graphmode of
CGAHI,MCGAHI: offset:=0;
VGAHI: offset:=15;
else offset:=10;
end;
setfillstyle(1,0);
bar(100,18 + offset,max_x,25 + offset);
moveto(((max_x - length(s)) div 2) - 60,18 + offset);
outtext(S);
end;
procedure clear_prompt;
begin
setfillstyle(1,0);
bar(1,1,max_x,8);
setcolor(2);
moveto(1,1);
end;
procedure out_prompt(s:string);
begin
clear_prompt;
outtext(s);
setcolor(15);
end;
procedure main_prompt;
begin
out_prompt('GRAPHICS: C(lear, T(ime plot, S(pectral plot, Q(uit');
end;
procedure time_plot;
var ch:char;
time_stamp,old_time_stamp:integer;
begin
old_time_stamp:=0;
out_prompt('Hit <SPACE BAR> to stop');
setfillstyle(1,0);
bar(1,scale_y(238),getmaxx,scale_y(260));
plot_title('T I M E P L O T');
count:=0;
remote_on;
reading:=get_s_reading;
moveto(X_INIT,scale_y(reading));
setcolor(11);
while not keypressed do
begin
gettime(hour,minute,sec,sec100);
time_stamp:=sec;
if (time_stamp <> old_time_stamp) then
begin
old_time_stamp:=time_stamp;
inc(count);
end;
reading:=get_s_reading;
lineto(X_INIT + count, scale_y(reading));
if count > max_count then
begin
count:=0;
moveto(X_INIT,scale_y(reading));
end;
end;
main_prompt;
ch:=fetch; { get key pressed and discard }
end;
procedure spectral_plot;
const BUFFERSIZE = 50;
var ok,nullval:boolean;
start,stop:integer;
delta:real;
last_freq, freq:real;
freq_range:real;
count_delta,count:integer;
i:integer;
s:string;
freq_buffer: array[1..BUFFERSIZE] of byte;
plot_cnt: buffer_type;
old_stat:receivertype;
ch:char;
procedure draw_x_axis;
const POINTS = 8;
var i,x:integer;
del:real;
s:string;
f:real;
begin
moveto(X_AXIS,scale_y(240));
lineto(max_x, scale_y(240));
del:=max_count / POINTS;
for i:=0 to POINTS do
begin
x:=round(X_AXIS + del * i);
moveto(x, scale_y(242));
lineto(x, scale_y(238));
moveto(x - 26, scale_y(250));
f:=start_freq + i * ((stop_freq - start_freq) / POINTS);
str(f:7:1,s);
outtext(s);
end;
end;
procedure radio_setup;
var s:string;
begin
old_stat:=receiverstat;
remote_on; { lock radio; cmd mode }
set_mode(CW);
set_bandwidth(NARR);
if freq_range <= 100.0 then s:='1' else s:='2';
set_tuning_rate(s);
set_agc(FAST);
set_freq(start_freq);
delay(200);
remote_off(0);
end;
procedure get_scan_range;
begin
start:=round(start_freq);
str(start_freq:5:0,s);
s:='starting frequency [default=' + s + ']';
entnum(1,5,start,ok,nullval,s);
if not ok then exit;
if not nullval then start_freq:=start;
stop:=round(stop_freq);
str(stop_freq:5:0,s);
s:='stopping frequency [default=' + s + ']';
entnum(1,7,stop,ok,nullval,s);
if not ok then exit;
if not nullval then stop_freq:=stop;
end;
procedure restore_radio; { to settings prior to spectral plot }
begin
remote_on;
with receiverstat do
set_all(199,attenuator,bandwidth,mode,frequency,agc);
set_tuning_rate('0'); { 1 Hz }
delay(100);
remote_off(REMOTE_DLY);
end;
procedure plot_point(freq:real; y:byte);
var x,ave:integer;
color:integer;
begin
{ adaptively Kalman filter reading to get statistical average }
{ the idea is to end up with a running average where the last }
{ point has no more influence than the first }
x:=round(max_count * ((freq - start_freq) / freq_range));
ave:=round((plot_cnt[x] * plot_buffer[x] + y) / (plot_cnt[x] + 1));
plot_buffer[x]:=ave;
if plot_cnt[x] < 255 then inc(plot_cnt[x]);
{ now draw point }
if y < 99 then color:=12 else color:=11;
putpixel(x + X_AXIS,scale_y(y),color);
end;
procedure draw_average;
var x:integer;
begin
moveto(X_AXIS,scale_y(plot_buffer[0]));
setcolor(14);
for x:=1 to max_count do if plot_buffer[x] > 0 then
lineto(x + X_AXIS,scale_y(plot_buffer[x]));
end;
procedure do_find(var ch:char);
const CURSOR_HEIGHT = 10;
TAB_COUNT = 25;
type shadetype = (NORMAL,HIGHLIGHT);
var x:integer;
p:pointer;
f:real;
keyfound:boolean;
last_x:integer;
procedure plot_point(x:integer; shade:shadetype);
var color:integer;
procedure hash_mark;
var ypos:integer;
begin
{ insure that exact cursor location is found }
if shade = NORMAL then x:=last_x;
{ get average point. set to x-axis if not plotted yet }
if plot_buffer[x] > 0
then ypos:=scale_y(plot_buffer[x])
else ypos:=scale_y(240);
if shade = NORMAL then { remove cursor }
putimage(x + X_AXIS - CURSOR_HEIGHT,
ypos - CURSOR_HEIGHT, p^, normalput)
else
begin
{ save image under cursor }
getimage(x + X_AXIS - CURSOR_HEIGHT,ypos - CURSOR_HEIGHT
,x + X_AXIS + CURSOR_HEIGHT,ypos + CURSOR_HEIGHT, p^);
{ draw cursor }
moveto(x + X_AXIS, ypos + CURSOR_HEIGHT);
lineto(x + X_AXIS, ypos - CURSOR_HEIGHT);
moveto(x + X_AXIS, ypos);
lineto(x + X_AXIS - CURSOR_HEIGHT, ypos);
moveto(x + X_AXIS, ypos);
lineto(x + X_AXIS + CURSOR_HEIGHT, ypos);
end;
last_x:=x;
end;
begin
case shade of
NORMAL: begin
color:=14;
setcolor(0);
end;
HIGHLIGHT: begin
color:=10;
setcolor(10);
end;
end;
hash_mark;
end;
procedure clear_receiver_status;
var offset:integer;
begin
{ compensate for low res displays to allow room for text }
case graphmode of
CGAHI,MCGAHI: offset:=0;
VGAHI: offset:=40;
else offset:=20;
end;
setfillstyle(1,0);
bar(100,25 + offset,max_x,36 + offset);
moveto(130,29 + offset);
end;
function freq_to_x(f:real):integer;
{ convert frequency to x coordinate }
var x:integer;
begin
x:=round(max_count * ((f - start_freq) / freq_range));
if x < 0 then x:=0;
if x > max_count then x:=max_count;
freq_to_x:=x;
end;
procedure show_receiver;
{ display receiver status at the top of the screen }
var s,s1:string;
begin
with receiverstat do
begin
str(frequency:8:2,s1);
s:='Frequency: ' + s1 +
' Mode: ' + mode_to_str(mode) +
' BW: ' + bandwidth_to_str(bandwidth) +
' AGC: ' + agc_to_str(agc);
end;
clear_receiver_status;
setcolor(3);
outtext(s);
end;
procedure tune_radio(f:real);
begin
{ remove cursor from old frequency }
x:=freq_to_x(receiverstat.frequency);
plot_point(x,NORMAL);
{ set the frequency }
remote_on;
set_freq(f);
delay(100);
remote_off(100);
toggle_remote;
show_receiver;
{ move cursor }
x:=freq_to_x(f);
plot_point(x, HIGHLIGHT);
end;
procedure inc_freq;
var f:real;
begin
f:=trunc(receiverstat.frequency/10.0) * 10.0;
if receiverstat.frequency - f >= 5.0 then f:=f + 5.0;
f:=f + 5.0;
if f > stop_freq then f:=stop_freq;
tune_radio(f);
end;
procedure dec_freq;
var f:real;
begin
f:=trunc(receiverstat.frequency/10.0) * 10.0;
if receiverstat.frequency - f > 5.0 then f:=f + 10.0
else if receiverstat.frequency - f > 0.0 then f:=f + 5.0;
f:=f - 5.0;
if f < start_freq then f:=start_freq;
tune_radio(f);
end;
procedure move_right(var keyfound:boolean;var ch:char; count:integer);
var f:real;
begin
{ unload the key buffer if its full to speed this up }
while keypressed and (ch in [RIGHTARROW, TAB]) do
begin
ch:=upcase(fetch);
case ch of
RIGHTARROW: inc(count);
TAB: count:=count + TAB_COUNT;
else keyfound:=TRUE;
end;
end;
f:=receiverstat.frequency + delta * count;
if f > stop_freq then f:=stop_freq;
tune_radio(f);
end;
procedure move_left(var keyfound:boolean;var ch:char; count:integer);
var f:real;
begin
{ unload the key buffer if its full to speed this up }
while keypressed and (ch in [LEFTARROW, BACKTAB]) do
begin
ch:=upcase(fetch);
case ch of
LEFTARROW: inc(count);
BACKTAB: count:=count + TAB_COUNT;
else keyfound:=TRUE;
end;
end;
f:=receiverstat.frequency - delta * count;
if f < start_freq then f:=start_freq;
tune_radio(f);
end;
begin
out_prompt('Find: C(ontinue, L(og, Q(uit');
draw_average;
if not SPECTRAL_MODE then
begin
receiverstat:=old_stat;
restore_radio;
end;
toggle_remote;
show_receiver;
{ init buffer for saving image under graphics cursor }
getmem(p,imagesize(100 - CURSOR_HEIGHT, 100 - CURSOR_HEIGHT
,100 + CURSOR_HEIGHT, 100 + CURSOR_HEIGHT));
x:=freq_to_x(receiverstat.frequency);
plot_point(x, HIGHLIGHT);
repeat
repeat
if async_buffer_check(ch) then { they touched the dial, etc }
begin
{ remove old cursor }
x:=freq_to_x(receiverstat.frequency);
plot_point(x, NORMAL);
check_status(s); { get new receiver status }
{ empty queue to compensate for graph drawing delay }
while async_buffer_check(ch) do check_status(s);
show_receiver;
{ move cursor }
x:=freq_to_x(receiverstat.frequency);
plot_point(x, HIGHLIGHT);
end;
until keypressed;
ch:=upcase(fetch);
keyfound:=FALSE;
repeat
case ch of
RIGHTARROW: move_right(keyfound, ch, 1);
LEFTARROW: move_left(keyfound, ch, 1);
TAB: move_right(keyfound, ch, 25);
BACKTAB: move_left(keyfound, ch, 25);
'>' ,'.': begin
inc_mode;
show_receiver;
end;
'<', ',': begin
dec_mode;
show_receiver;
end;
']': begin
inc_bandwidth;
show_receiver;
end;
'[': begin
dec_bandwidth;
show_receiver;
end;
'+': inc_freq;
'-': dec_freq;
end;
until not keyfound;
until ch in ['C','L','Q'];
{ remove cursor before leaving }
x:=freq_to_x(receiverstat.frequency);
plot_point(x,NORMAL);
SPECTRAL_MODE:=ch = 'L';
old_stat:=receiverstat;
clear_receiver_status;
if ch = 'C' then
begin
radio_setup;
remote_on;
set_freq(last_freq);
remote_off(0);
end;
out_prompt('COMMANDS: C(lear, F(ind, Q(uit');
dispose(p);
end;
procedure init_spectral_plot;
begin
init_graph;
out_prompt('COMMANDS: A(verage, C(lear, F(ind, Q(uit');
plot_title('S P E C T R A L P L O T');
draw_x_axis;
end;
begin
if not SPECTRAL_MODE then
begin
restorecrtmode;
home;
writea(LIGHTGREEN,FOREGROUND);
writeln(output,' SPECTRAL PLOT: Enter the frequency range to scan');
get_scan_range;
end;
init_spectral_plot;
freq_range:=stop_freq - start_freq;
if not SPECTRAL_MODE then radio_setup;
{ init plot statistics used to Kalman filter averages }
for i:=0 to max_count do
begin
if not SPECTRAL_MODE then plot_buffer[i]:=0;
plot_cnt[i]:=0;
end;
last_freq:=start_freq;
ch:=' ';
if SPECTRAL_MODE then do_find(ch);
if not SPECTRAL_MODE and (ch <> 'Q') then repeat
remote_on;
delay(1000);
count:=0;
set_auto_tune('+');
{ gather data }
while (count < BUFFERSIZE) do
begin
inc(count);
freq_buffer[count]:=get_s_reading;
end;
remote_off(0);
toggle_remote;
delay(300);
while async_buffer_check(ch) do check_status(s); { get frequency }
freq:=receiverstat.frequency;
if freq > stop_freq then
begin
remote_on;
set_freq(start_freq);
delay(1000);
end;
remote_off(0);
delta:=(freq - last_freq) / BUFFERSIZE;
{ plot buffer contents }
count:=0;
freq:=last_freq;
while (freq < stop_freq) and (count < BUFFERSIZE) do
begin
inc(count);
plot_point(freq, freq_buffer[count]);
freq:=freq + delta;
end;
last_freq:=receiverstat.frequency;
if last_freq > stop_freq then last_freq:=start_freq;
while keypressed do
begin
ch:=upcase(fetch);
case ch of
'F': do_find(ch);
'A': draw_average;
'C': init_spectral_plot;
end;
end;
until (ch = 'Q') or SPECTRAL_MODE;
if not SPECTRAL_MODE then
begin
receiverstat:=old_stat;
restore_radio;
end;
main_prompt;
end;
begin
if radio_type <> 535 then exit;
max_x:=getmaxx - 30; max_y:=getmaxy;
max_count:=max_x - X_AXIS;
last_plot:=NONE;
if SPECTRAL_MODE then spectral_plot
else
begin
init_graph;
main_prompt;
start_freq:=receiverstat.frequency - 5.0;
stop_freq :=receiverstat.frequency + 5.0;
end;
if not SPECTRAL_MODE then
begin
repeat
if keypressed then ch:=upcase(fetch) else ch:='@' { nop };
case ch of
'@':; { nop }
'C':begin
init_graph;
main_prompt;
end;
'T':time_plot;
'S':spectral_plot;
end;
until (ch = 'Q') or SPECTRAL_MODE;
end;
restorecrtmode;
init_crt;
remote_off(0); { unlock radio }
if async_buffer_check(ch) then comreadln(COM_NRD,s);
information_mode_on;
gotoxy(x_pos,y_pos);
show_log(rec,TRUE,TRUE);
end;
begin
end.